#include <iostream>
#include <vector>
#include <fstream>
#include "Nodo.cpp"
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <sstream>

using namespace std;

#ifndef __GRAFO__
#define __GRAFO__

class Grafo {
public:

    Grafo() {
        this->nodos.clear();
    };

    Grafo(const Grafo& orig);

    virtual ~Grafo() {
    }

    /** Agrega un nodo con id id a la lista de nodos de this. Si ya existe un
     * nodo con id id el nodo no es agregado.
     * 
     * @param id id del nodo que se quiere agregar
     * @return true si el nodo se agrega, false en caso contrario.
     */
    bool agregarNodo(int id) {
        for (vector<Nodo*>::iterator i = this->nodos.begin();
                i != this->nodos.end(); i++) {
            if (id == (*i)->getId()) {
                return false; // Ya esta agregado
            }
        }
        Nodo * n = new Nodo(id);
        this->nodos.push_back(n);
        // cout << "Nodo agregado: " << n->getId() << ", la cantidad de nodos es: " << this->nodos.size() << endl;
        return true;
    };

    /** Agrega un lado entre el nodo con id == fuente y el nodo con id == destino
     * 
     * @param fuente id del nodo fuente
     * @param destino id del nodo destino
     * @return true si se agrego el lado, false si no existe alguno de los 2 nodos o
     *  si el lado ya estaba
     */
    bool agregarLado(int fuente, int destino) {
        // cout << "Agregando arco desde " << fuente << " a " << destino << endl;
        Nodo * f, * d;
        bool fFound = false, dFound = false;
        for (vector<Nodo*>::iterator i = this->nodos.begin();
                i != this->nodos.end(); i++) {
            //            // cout << "Voy pa la siguiente iteracion" << endl;
            if (fuente == (*i)->getId()) {
                //                // cout << "Encontre el fuente" << endl;
                f = *i; // Encontre el fuente
                //                // cout << "Asigne apuntador " << endl;
                fFound = true;
            }
            if (destino == (*i)->getId()) {
                //                // cout << "Encontre el destino" << endl;
                d = *i; // Encontre el destino
                //                // cout << "Asigne apuntador " << endl;
                dFound = true;
            }
            if (fFound && dFound) {
                //                // cout << "Encontre ambos" << endl;
                break;
            }
        }
        if (fFound && dFound) {
            if (!f->agregarAdyacente(d)) {
                return false;
            }
            if (!d->agregarAdyacente(f)) {
                f->eliminarAdyacente(d);
                return false;
            }
            //            // cout << "Adyacentes agregados" << endl;
            //            // cout << f->getId() << " tiene " << f->getAdyacentes().size() << " sucesores" << endl;
            //            // cout << d->getId() << " tiene " << d->getAdyacentes().size() << " sucesores" << endl;
            return true;
        } else {
            //            // cout << "Nodos no encontrados" << endl;
            return false;
        }
    }

    vector<Nodo*> * getNodos() {
        return &this->nodos;
    };

    void imprimir() {
      cout << "Nodo\tColor" << endl;
        for (vector<Nodo*>::iterator i = this->nodos.begin();
                i != this->nodos.end(); i++) {
          cout << (*i)->getId() << "\t" << (*i)->getColor()  << endl;
        }
        cout << endl;
    }

    /** Recibe la ruta a un archivo que contiene un grafo en formato DIMACS
     * y lo carga en this.
     * 
     * @param archivo
     * @param g
     * @return 
     */
    bool cargarGrafo(string archivo, Grafo & g) {

        string linea;
        string primero, segundo, tercero;
        ifstream miarchivo(archivo.c_str());
        if (miarchivo.is_open()) {
            while (miarchivo.good()) {
                getline(miarchivo, linea);

                istringstream lineass(linea);
                lineass >> primero >> segundo >> tercero;

                if (primero.compare("e") == 0) {
                    int i = atoi(segundo.c_str());
                    int j = atoi(tercero.c_str());
                    g.agregarNodo(i);
                    g.agregarNodo(j);
                    g.agregarLado(i, j);
                }

            }
            miarchivo.close();
        } else {
            return false;
        }
        return true;
    }

private:

    vector<Nodo*> nodos;

};

#endif